package com.qh.paythird.wxpay.utils;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.xml.sax.InputSource;

import com.thoughtworks.xstream.XStream;

import java.io.IOException;
import java.io.StringReader;
import java.util.List;
import java.util.SortedMap;
import java.util.StringTokenizer;
import java.util.TreeMap;

/**
 * Created by 梦想达到
 * 描述:微信返回的结果为Xml格式的字符串，XmlUtil主要用于解析结果
 */

public class XMLUtil {

    public static Object getObjectFromXML(String xml, Class tClass) {
        //将从API返回的XML数据映射到Java对象
        XStream xStreamForResponseData = new XStream();
        xStreamForResponseData.alias("xml", tClass);
        //配置忽略object中不存在的字段
        xStreamForResponseData.ignoreUnknownElements();
        return xStreamForResponseData.fromXML(xml);
    }

    /**
     * 读取本地的xml数据，一般用来自测用
     * @param localPath 本地xml文件路径
     * @return 读到的xml字符串
     */
    public static String getLocalXMLString(String localPath) throws IOException {
        return Util.inputStreamToString(Util.class.getResourceAsStream(localPath));
    }

    public static SortedMap<String, String> xmlToMap(String xml){
        SortedMap<String, String> map = new TreeMap<String, String>();
        try {
            Document result = null;
            SAXReader reader = new SAXReader();
            String encoding = getEncoding(xml);
            InputSource source = new InputSource(new StringReader(xml));
            source.setEncoding(encoding);
            //xxe漏洞修复
            reader.setFeature("http://apache.org/xml/features/disallow-doctype-decl",true);
            reader.setFeature("http://xml.org/sax/features/external-general-entities",false);
            reader.setFeature("http://xml.org/sax/features/external-parameter-entities",false);
            reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd",false);
            result = reader.read(source);
            if(result.getXMLEncoding() == null) {
                result.setXMLEncoding(encoding);
            }
            Element root = result.getRootElement();

            @SuppressWarnings("unchecked")
            List<Element> list = root.elements();
            for (Element e : list) {
                map.put(e.getName(), e.getText());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }

    private static String getEncoding(String text) {
        String result = null;
        String xml = text.trim();
        if(xml.startsWith("<?xml")) {
            int end = xml.indexOf("?>");
            String sub = xml.substring(0, end);
            StringTokenizer tokens = new StringTokenizer(sub, " =\"'");

            while(tokens.hasMoreTokens()) {
                String token = tokens.nextToken();
                if("encoding".equals(token)) {
                    if(tokens.hasMoreTokens()) {
                        result = tokens.nextToken();
                    }
                    break;
                }
            }
        }

        return result;
    }

    public static void main(String[] args) {
        String xml = "<xml><appid><![CDATA[wx597d9f0a67692910]]></appid>"+
        "<bank_type><![CDATA[CFT]]></bank_type>"+
        "<cash_fee><![CDATA[1]]></cash_fee>"+
        "<fee_type><![CDATA[CNY]]></fee_type>"+
        "<is_subscribe><![CDATA[Y]]></is_subscribe>"+
        "<mch_id><![CDATA[1482418422]]></mch_id>"+
        "<nonce_str><![CDATA[5o34r2n3hubzbn9gnwa7zcyxd3tuplsh]]></nonce_str>"+
        "<openid><![CDATA[oTZZ0wP16pIBEY5eQEg33HCQeTqw]]></openid>"+
        "<out_trade_no><![CDATA[NFZF14000441708251417396994]]></out_trade_no>"+
        "<result_code><![CDATA[SUCCESS]]></result_code>"+
        "<return_code><![CDATA[SUCCESS]]></return_code>"+
        "<sign><![CDATA[9F3B60336CA7AE8CD65686777610E5E3]]></sign>"+
        "<time_end><![CDATA[20170825141757]]></time_end>"+
        "<total_fee>1</total_fee>"+
        "<trade_type><![CDATA[JSAPI]]></trade_type>"+
        "<transaction_id><![CDATA[4008742001201708258161927430]]></transaction_id>"+
        "</xml>";
        SortedMap<String, String> map = xmlToMap(xml);
        System.out.print("success");
    }
}